#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import json

from common import common
from common.const import RepositoryDataTypeEnum
from common.logger import Logger
from db2.comm.const import Db2Const, Db2JobName, Db2JsonConstant
from db2.comm.constant import ParamField, HadrRoleType
from db2.comm.util.common_util import Db2CommonUtil
from db2.comm.util.param_util import Db2ParamUtil

LOGGER = Logger().get_logger(filename="db2.log")


class HadrParseRestoreParams:

    def __init__(self, task_name, pid, job_id, sub_job_id, param_dict):
        self.task_name = task_name
        self.pid = pid
        self.job_id = job_id
        self.sub_job_id = sub_job_id
        self.cache_path = ""
        self.param_dict = param_dict
        self.init_params()

    @staticmethod
    def get_host_id_from_host_node(node):
        """获取节点所在主机的host id信息"""
        host_id = node.get(ParamField.ID, "")
        return host_id

    @staticmethod
    def get_db_name_from_database_node(node):
        """获取节点数据库名称"""
        db_name = node.get(ParamField.NAME, "")
        if common.check_command_injection_ex_quote_space(db_name):
            raise Exception("Param of node(db_name) invalid")
        return db_name

    @staticmethod
    def get_instance_name_from_database_node(node):
        """获取节点数据库所属实例名称"""
        instance_name = node.get(ParamField.PARENT_NAME, "")
        if common.check_command_injection(instance_name):
            raise Exception("Param of node(instance_name) invalid")
        return instance_name

    @staticmethod
    def get_hadr_role_from_database_node(node):
        """获取节点数据库主备类型"""
        node_role = node.get(ParamField.EXTEND_INFO, {}).get(ParamField.HADR_ROLE, "")
        if node_role in (HadrRoleType.PRIMARY, HadrRoleType.STANDBY):
            return node_role
        if node_role == "1":
            return HadrRoleType.PRIMARY
        elif node_role == "2":
            return HadrRoleType.STANDBY
        else:
            raise Exception("Param of node(node_role) invalid")

    @staticmethod
    def get_local_db_directory_from_database_node(node):
        """获取节点数据库所属实例路径"""
        local_db_directory = node.get(ParamField.EXTEND_INFO, {}).get(ParamField.LOCAL_DATABASE_DIRECTORY, "")
        if common.check_command_injection(local_db_directory):
            raise Exception("Param of node(local_db_directory) invalid")
        return local_db_directory

    @staticmethod
    def get_timestamp_from_copy(copy):
        """从副本信息获取副本时间戳"""
        bak_img_timestamp = copy.get(ParamField.EXTEND_INFO, {}).get(ParamField.BACKUP_TIMESTAMP, "")
        if common.check_command_injection(bak_img_timestamp):
            raise Exception("Param of copy(bak_img_timestamp) invalid")
        return bak_img_timestamp

    @staticmethod
    def get_uuid_from_copy(copy):
        """从副本信息获取生成该副本的主机uuid"""
        exendinfo = copy.get(ParamField.EXTEND_INFO, {})
        uuid = exendinfo.get(ParamField.UUID, "")
        if common.check_command_injection(uuid):
            raise Exception("Param of copy(uuid) invalid")
        return uuid

    @staticmethod
    def get_redirect_cont(copy, node):
        """生成重定向参数"""
        original_install_path = copy.get(ParamField.EXTEND_INFO, {}).get(ParamField.LOCAL_DATABASE_DIRECTORY, "")
        if not original_install_path:
            original_install_path = copy.get(ParamField.EXTEND_INFO, {}).get(ParamField.EXTEND_INFO, {}) \
                .get(ParamField.LOCAL_DATABASE_DIRECTORY, "")
        target_install_path = node.get(ParamField.EXTEND_INFO, {}).get(ParamField.LOCAL_DATABASE_DIRECTORY, "")
        LOGGER.info(f"original_install_path: {original_install_path}, target_install_path: {target_install_path}")
        if original_install_path == target_install_path:
            return ""
        return Db2Const.REDIRECT

    @staticmethod
    def get_db_name_from_copy(copy):
        """从副本获取数据库名称"""
        db_name = copy.get(Db2JsonConstant.PROTECT_OBJECT, {}).get(Db2JsonConstant.NAME, "")
        if common.check_command_injection(db_name):
            raise Exception("Param of copy(db_name) invalid")
        return db_name

    @staticmethod
    def get_data_path(copy_info):
        copy_path = copy_info.get(ParamField.DATA_PATH, "")
        if common.check_command_injection(copy_path):
            raise Exception("Param of copy_info(copy_path) invalid")
        return copy_path

    @staticmethod
    def get_restore_time(copy_info):
        copy_timestamp = copy_info.get(ParamField.RESTORE_TIME, "")
        if common.check_command_injection(copy_timestamp):
            raise Exception("Param of copy_info(restore_time) invalid")
        return copy_timestamp

    def init_params(self):
        if self.task_name != Db2JobName.ALLOW_RESTORE_IN_LOCAL:
            self.get_cache_mount_path_for_restore()

    def get_log_comm(self):
        return f"pid: {self.pid} jobId: {self.job_id} subjobId: {self.sub_job_id}."

    def get_job(self):
        """从参数中获取JOB信息"""
        job = self.param_dict.get(ParamField.JOB, {})
        if not job:
            raise Exception("Param of job invalid")
        return job

    def get_original_host_nodes(self):
        """获取副本所属集群所有节点信息"""
        original_host_nodes = self.get_copies()[-1].get(ParamField.PROTECT_ENV, {}).get(ParamField.NODES, [])
        if not original_host_nodes:
            raise Exception("Param of original_nodes invalid")
        return original_host_nodes

    def get_target_env(self):
        """获取待恢复集群环境信息"""
        target_env = self.param_dict.get(ParamField.JOB, {}).get(ParamField.TARGET_ENV, {})
        if not target_env:
            raise Exception("Param of target_env invalid")
        return target_env

    def get_target_database_nodes(self):
        """获取待恢复集群节点数据库信息"""
        database_nodes = self.get_target_env().get(ParamField.EXTEND_INFO, {}).get(ParamField.NODE_DATABASE, "")
        database_nodes = json.loads(database_nodes)
        if len(database_nodes) <= 0:
            raise Exception("Param of target nodes invalid")
        return database_nodes

    def get_target_host_nodes(self):
        host_nodes = self.get_target_env().get(ParamField.NODES, {})
        if len(host_nodes) <= 0:
            raise Exception("Param of target host_nodes invalid")
        return host_nodes

    def get_sub_job(self):
        """获取子任务信息"""
        return self.param_dict.get(ParamField.SUBJOB, {})

    def get_sub_job_name(self):
        """获取子任务名称"""
        return self.get_sub_job().get(ParamField.JOBNAME, "")

    def get_copies(self):
        """获取所有副本信息"""
        copies = self.param_dict.get(ParamField.JOB, {}).get(ParamField.COPYIES, [])
        if not copies:
            raise Exception("Param of copies invalid")
        return copies

    def get_log_restore_timestamp(self):
        """获取日志恢复的时间点"""
        restore_timestamp = self.get_job().get(ParamField.EXTEND_INFO, {}).get(ParamField.RESTORE_TIMESTAMP, "")
        if common.check_command_injection(restore_timestamp):
            raise Exception("Param of extendInfo(restore_timestamp) invalid")
        return restore_timestamp

    def get_last_data_copy_repositories(self):
        """获取最后一个数据副本的挂载信息"""
        copies = self.get_copies()
        data_copy = copies[-1]
        timestamp = self.get_log_restore_timestamp()
        if timestamp:
            # 日志恢复
            if len(copies) < 2:
                data_copy = copies[-2]
        repositories = data_copy.get(ParamField.REPOSITORIES, [])
        if not repositories:
            raise Exception("Param of copy(repositories) invalid")
        return repositories

    def get_restore_mount_path(self, rep_type):
        """根据恢复类型获取挂载路径"""
        repositories = self.get_last_data_copy_repositories()
        mount_path = Db2CommonUtil.get_designated_mount_path(rep_type, repositories)
        if not mount_path:
            raise Exception("Param of copy(mount_path) invalid")
        return mount_path

    def get_cache_mount_path_for_restore(self):
        self.cache_path = Db2ParamUtil.get_cache_mount_path_for_restore(self.param_dict)
        if common.check_command_injection(self.cache_path):
            raise Exception("Param of repositories(cache) invalid")

    def get_cache_path(self):
        """根据恢复类型获取cache仓挂载路径"""
        return self.get_restore_mount_path(RepositoryDataTypeEnum.CACHE_REPOSITORY)

    def get_target_location(self):
        """根据恢复类型目标位置参数(原位置、新位置)"""
        return self.get_job().get(ParamField.EXTEND_INFO, {}).get(ParamField.TARGETLOCATION, "")

    def get_restore_ts(self):
        """根据待恢复表空间信息"""
        res_ts_names = Db2ParamUtil.get_restore_table_spaces(self.param_dict)
        ts_names_str = ",".join(res_ts_names)
        if common.check_command_injection(ts_names_str):
            raise Exception("Param of targetObject(res_ts_names) invalid")
        return ts_names_str
